---
title: Server vs Client
description: Understand the difference between server and client rendering.
---

<Info>
This page is only relevant when using **static** or **server** mode.
</Info>

---

When using Jaspr in **static** or **server** mode, your app will be executed both on the server (as native code or running in the Dart VM) and on the client (compiled to either JS or WASM), with some parts being run in both environments and some in only one.

As a result, some or your components will be:

- **only rendered on the server**
- **rendered both on the server and client** 
- **only rendered on the client** (almost never happens though).

<Info>
  The terms "server" and "client" in this context refer to the environment in which the code is executed, not the actual hardware running it. Specifically, the "server" environment is the same whether you run it on your local machine (during development), a CI pipeline (in "static" mode) or an actual webserver (in "server" mode).
</Info>

Learning about and understanding the differences between these environments, and what causes a component to be rendered in which environment is crucial to building a successful app with Jaspr.

## Difference between Server and Client

The main difference between the server and client environments are the platform libraries from the Dart SDK that are available:

- The server environment has access to [Native platform libraries](https://dart.dev/libraries#native-platform-libraries)
- The client environment has access to [Web platform libraries](https://dart.dev/libraries#web-platform-libraries)
  
Therefore, accessing a web-specific library like `dart:js_interop` in a server-rendered component will result in a compilation error. 

If you must access one of these libraries in a component that is rendered in both environments, you have several options:

1. When using [`package:web`](https://pub.dev/packages/web) you should instead use [`package:universal_web`](https://pub.dev/packages/universal_web) which already works across web **and server** environments. No need to use conditional imports or the `@Import` annotation shown below.
2. You can use the [`@Import`](/api/utils/at_import) annotation to import the correct library depending on the environment. This is a shorthand for using [conditional imports](https://dart.dev/guides/libraries/create-packages#conditionally-importing-and-exporting-library-files) and is the recommended way to do this in Jaspr.
3. You can use Dart's [conditional imports](https://dart.dev/guides/libraries/create-packages#conditionally-importing-and-exporting-library-files) to import the correct library depending on the environment. This is a more verbose way of doing the same thing as the `@Import` annotation, but is still valid.

---

Additionally, there are some Jaspr features that are only available in one of the environments. For example:

- Any `event` handlers will only be fired on the client.
- `setState()` may only be called on the client.
- The `Document()` component is only available on the server.
- The `AsyncStatelessComponent` and `AsyncBuilder` components are only available on the server.

## Where is my component rendered?

To write components that works in one or both environments, you need to understand how Jaspr decides where to render your components (or how you control it).

By default, you can reason about your components as follows:

1. Your apps entrypoint is `main.dart`. This is only executed on the server. Hence all components that are rendered from there (the root `Document` component and all its descendents) are rendered on the server.
2. Go through the component tree top down, starting at the root component and moving downwards through its descendents.
3. Any component annotated with `@client` is a client component. In addition to being rendered on the server, it is also attached as a root component on the client. This means:
  - It will be rendered both on the server and client.
  - All of its descendents are also rendered both on the server and client.

To find out if a particular component is rendered on the server or client, you can turn this around and move up the tree:

1. Start at the component you want to check.
2. If it or one of its ancestors is a client component, it is rendered on both the server and client.
3. Else, it is only rendered on the server.

<Info>
  Therefore `@client` components act as a sort of boundary. Everything below in the tree is rendered in both environments, while everything above is only rendered on the server.
</Info>

---

To reiterate:

1. Components rendered **only on the server** can safely:
  - use server-side Jaspr features like `Document()`  and `AsyncStatelessComponent`.
  - import and use server-specific libraries like `dart:io`.
  - access the filesystem, connect to a database etc.

2. Components rendered **both on the server and client** can:
  - use client-side Jaspr features like `setState()`.
  - use `kIsWeb` to check if the code is running on the client.
  - **neither** import client- nor server-specific libraries directly. 
    Instead, they must use one of the options mentioned above to import the correct library depending on the environment.

---

For more info regarding this topic, check out the following pages:

- [Hydration](/concepts/hydration)
- [`@client`](/api/utils/at_client)
- [`@Import`](/api/utils/at_import)
